package com.imdroid.carac.activities;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

import android.annotation.SuppressLint;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.MediaRecorder;
import android.os.Handler;
import android.os.StatFs;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.SurfaceView;
import android.widget.Toast;

import com.baidu.location.BDLocation;
import com.imdroid.carac.IMDroid;
import com.imdroid.carac.R;
import com.imdroid.carac.net.Weixin;

public class Record {

	/**
	 * The tag of this object
	 */
	private static final String TAG = "Record";
	private static LinkedList<Integer> recordResolutions = new LinkedList<Integer>(
			Arrays.asList((Integer) 1280, 720, 640, 480, 800, 480, 960, 720));
	private static LinkedList<Integer> fps = new LinkedList<Integer>(
			Arrays.asList((Integer) 0, 4, 8, 10, 16, 20, 25, 30));
	private static Map<String, String> cameraParams = new HashMap<String, String>();
	private static int ExposureCompensation;

	private static Handler handler = new Handler(IMDroid.getContext()
			.getMainLooper());
	private static Runnable task = new Runnable() {
		public void run() {
			stop();
			start();
		}
	};
	public static boolean needRecord = false;
	static Camera camera;
	private static MediaRecorder recorder;

	private static SensorManager sensorManager;
	private static Sensor accelerometer;
	private static SensorEventListener listener = new SensorEventListener() {
		public void onSensorChanged(SensorEvent event) {
			Record.onSensorChanged( event );
		}
		public void onAccuracyChanged(Sensor sensor, int accuracy) {
		}
	};
	private static double maxShock;
	private static String videoFileName;

	static void initParams() {
		recordResolutions = new LinkedList<Integer>(Arrays.asList(
				(Integer) 1280, 720, 640, 480, 800, 480, 960, 720));
		fps = new LinkedList<Integer>(Arrays.asList((Integer) 0, 4, 8, 10, 16,
				20, 25, 30));
		cameraParams = new HashMap<String, String>();
		ExposureCompensation = 0;
	}

	static {
//		final UncaughtExceptionHandler old = Thread.getDefaultUncaughtExceptionHandler();
//		Thread.setDefaultUncaughtExceptionHandler( new UncaughtExceptionHandler() {
//			public void uncaughtException(Thread thread, Throwable ex) {
//				old.uncaughtException(thread, ex);
//				stop();
//			}
//		} );
		
		initParams();
		
		new Thread() { public void run() {
			Thread.currentThread().setPriority( Thread.MIN_PRIORITY + 1 );
			while( true ) {
				try {
					Thread.sleep( 5 * 60 * 1000 );
				} catch (InterruptedException e) {
					throw new RuntimeException( e );
				}
				removeVideoFiles();
			}
		} }.start();
	}

	public static void init() {
	}

	// 开始录像
	public static void start() {
		needRecord = true;
		startCamera();
		startRecord();
		startTimer();
		FloatView.start();

		if( sensorManager == null )
			sensorManager = (SensorManager) IMDroid.getContext().getSystemService(IMDroid.SENSOR_SERVICE);
		if( accelerometer == null )
			accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
		sensorManager.registerListener( listener, accelerometer, Sensor.TYPE_ACCELEROMETER);
		maxShock = 0;
	}

	// 暂停录像
	public static void pause() {
		needRecord = true;
		FloatView.stop();
		stopTimer();
		stopRecord();
		stopCamera();

		if( sensorManager != null )
			sensorManager.unregisterListener( listener );
	}

	// 停止录像
	public static void stop() {
		needRecord = false;
		FloatView.stop();
		stopTimer();
		stopRecord();
		stopCamera();

		if( sensorManager != null )
			sensorManager.unregisterListener( listener );
	}

	// 拍照
	public static void takePicture() {
		stopTimer();
		stopRecord();

		camera.takePicture(null, null, null, new Camera.PictureCallback() {
			public void onPictureTaken(final byte[] data, Camera camera1) {
				// 这是 UI 线程，随后的事件
				startRecord();
				startTimer();

//				// 发微博
//				new Thread() {
//					public void run() {
//						File file = new File(
//								IMDroid.REC_PIC_FOLDER,
//								String.format(
//										"%1$tY-%1$tm-%1$td %1$tH.%1$tM.%1$tS.jpg",
//										Calendar.getInstance()));
//						try {
//							FileOutputStream out = new FileOutputStream(file);
//							out.write(data);
//							out.close();
//						} catch (IOException e) {
//							throw new RuntimeException(e);
//						}
//						Weibo.sendNoAuth(String.format(
//								"英卓车载行车拍照%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS",
//								Calendar.getInstance()), file.getAbsolutePath());
//					}
//				}.start();
				
				// 发微信
//				new Thread() { public void run() {
					File file = new File( IMDroid.REC_PIC_FOLDER, String.format( "%1$tY-%1$tm-%1$td %1$tH.%1$tM.%1$tS.jpg", Calendar.getInstance() ) );
					try {
						FileOutputStream out = new FileOutputStream(file);
						out.write(data);
						out.close();
					} catch (IOException e) {
						throw new RuntimeException(e);
					}
					
					try {
						Weixin.send( file.getCanonicalPath() );
					} catch (IOException e) {
						Toast.makeText(IMDroid.getContext(), "发微信失败："+e.getMessage(), Toast.LENGTH_LONG).show();
						Log.e("发微信失败：", ""+e);
					}
//				} }.start();
			}
		} );
	}

	// 打开摄像头
	private static void startCamera() {
		if (camera != null)
			return;
		try {
			// 找第一个前摄像头
			int n = Camera.getNumberOfCameras();
			Camera.CameraInfo info = new Camera.CameraInfo();
			int i = 0;
			for( ; i < n; i ++ ) {
				Camera.getCameraInfo( i, info );
				if( info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT )
					break;
			}
			// 找不到则用第一个
			if( i >= n )
				i = 0;
			 camera = Camera.open(0 );
			 camera.setDisplayOrientation(180);
			
			// 返回后摄像头，没有则返回 null
//			camera = Camera.open();
			// // 测试样机只有一个后广角摄像头，系统里面当作前摄像头，所以返回 null，这种情况下使用第一个可用的摄像头
			// if (camera == null)
//			camera = Camera.open( 0 );

			if (camera == null)
				throw new Exception("找不到摄像头");
		} catch (Exception e) {
			Log.e(Record.class.getName(), e.getMessage(), e);
			Toast.makeText(IMDroid.getContext(), "摄像头出错：" + e.getMessage(),
					Toast.LENGTH_LONG).show();
			return;
		}

		// 按时间自动设置参数
		Parameters params = camera.getParameters();
		int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
		if (7 <= hour && hour <= 19) { // 白天
			// 根据测试结果修改这些参数
		} else { // 夜晚
			// params.set( "brightness", "high" );
			// params.set( "contrast", "high" );
			// params.set( "iso-speed", "1600" );
			params.set("exposure", "-1.3");
			params.setExposureCompensation(-1);
		}

		// 然后恢复上段录像时手工改动过的参数，注意会覆盖上面按时间自动设置的参数
		for (Map.Entry<String, String> e : cameraParams.entrySet())
			params.set(e.getKey(), e.getValue());
		params.setExposureCompensation(ExposureCompensation);
		camera.setParameters(params);

		// // 据说下面的代码可以禁用自动曝光，实际测试没发现效果
		// Parameters params = camera.getParameters();
		// params.setAutoExposureLock( true );
		// camera.setParameters( params );
	}

	// 开始录像
	private static void startRecord() {
		if (camera == null)
			return;
		if (recorder != null)
			return;

		camera.unlock();
		recorder = new MediaRecorder();
		recorder.setOrientationHint(180);
		recorder.setCamera(camera);
		recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
		recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
		recorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
		videoFileName = getVideoFileName();
		recorder.setOutputFile(videoFileName);
		// 不要录声音，不能使用 recorder.setProfile(
		// CamcorderProfile.get(CamcorderProfile.QUALITY_LOW ) )
		// recorder.setVideoSize( 960, 720 );
		recorder.setVideoSize(recordResolutions.get(0),
				recordResolutions.get(1));
		if (!fps.getFirst().equals(0))
			recorder.setVideoFrameRate(fps.getFirst());

		// 自动选择适合的 SurfaceView，优先选择 RecordActivity.surfaceView 这个大屏
		SurfaceView sv = RecordActivity.surfaceView;
		// 不行再选浮动窗
		if (sv == null)
			sv = FloatView.surfaceView;
		// if (sv == null)
		// throw new RuntimeException( "浮动窗尚未显示" );
		recorder.setPreviewDisplay(sv.getHolder().getSurface());

		try {
			recorder.prepare();
		} catch (IOException e) {
			Toast.makeText(IMDroid.getContext(), "录像出错：" + e.getMessage(),
					Toast.LENGTH_LONG).show();
			recorder = null;
			return;
		}
		recorder.start();
	}

	// 定时停开录像
	private static void startTimer() {
		if (camera == null)
			return;
		if (recorder == null)
			return;
		stopTimer();

		// 取得每个文件最大录像时间
		int maxSingleRecordTime = PreferenceManager
				.getDefaultSharedPreferences(IMDroid.getContext()).getInt(
						IMDroid.getContext().getResources()
								.getString(R.string.KEY_REC_FILE_LEN), 5 * 60);
		maxSingleRecordTime *= 1000;
		// maxSingleRecordTime = 2 * 60 * 1000;

		handler.postDelayed(task, maxSingleRecordTime);
	}

	private static void stopTimer() {
		handler.removeCallbacks(task);
	}

	// 停止录像
	private static void stopRecord() {
		if (recorder == null)
			return;
		recorder.stop();
		recorder.release();
		recorder = null;
		new File(videoFileName).renameTo( new File( videoFileName.replaceFirst("GGG", String.format("%.2f",maxShock) ) ) );
	}

	// 关闭摄像头
	private static void stopCamera() {
		if (camera == null)
			return;
		camera.release();
		camera = null;
	}

	@SuppressLint("SimpleDateFormat")
	private static String getVideoFileName() {
		// 文件名加上位置信息
		BDLocation location = null;
		try {
			location = IMDroid.getCurrentLocation();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return String.format("%s%s_%.6f-%.6f-%.6f_GGG.3gp", IMDroid.VIDEO_FOLDER,
				new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()),
				location == null ? .0 : location.getLongitude(),
				location == null ? .0 : location.getLatitude(),
				location == null ? .0 : location.getAltitude());
	}

	private static void removeVideoFiles() {
		// 剩余空间比较少了就要删
		StatFs sf = new StatFs(IMDroid.VIDEO_FOLDER);
		long freeSpace = sf.getAvailableBlocks() * (long) sf.getBlockSize();
		if( freeSpace > 500 * 1024 * 1024 )
			return;

//		// 获取能保存的最大文件数
//		final int maxFileCount = PreferenceManager.getDefaultSharedPreferences(
//				IMDroid.getContext()).getInt(
//				IMDroid.getContext().getResources()
//						.getString(R.string.KEY_REC_FILE_COUNT), 60);

		LinkedList<File> files = new LinkedList<File>( Arrays.asList( new File(IMDroid.VIDEO_FOLDER).listFiles() ) );
		// 先按G值从小到大排序
		Collections.sort(files, new Comparator<File>() {
			public int compare(File f1, File f2) {
				float g1 = 0;
				String[] ss = f1.getName().substring(0, f1.getName().length()-4).split("_");
				if( ss.length > 2 )
					g1 = Float.parseFloat( ss[2] );
				float g2 = 0;
				ss = f1.getName().substring(0, f1.getName().length()-4).split("_");
				if( ss.length > 2 )
					g2 = Float.parseFloat( ss[2] );
				if( g1 > g2 )
					return +1;
				if( g1 < g2 )
					return -1;
				return 0;
			}
		} );
		// 后10个，即G值最大的10个文件要留着
		for( int i = 0; i < 10; i ++ )
			if( ! files.isEmpty() )
				files.removeLast();
		// 剩下的允许删除的文件，按时间排序
		Collections.sort(files, new Comparator<File>() {
			public int compare(File f1, File f2) {
				long t1 = f1.lastModified();
				long t2 = f2.lastModified();
				if (t1 > t2)
					return +1;
				if (t1 < t2)
					return -1;
				return 0;
			}
		} );
		// 删到剩余空间比较多了才停止
		for( File file : files ) {
			freeSpace += file.length();
			file.delete();
			if( freeSpace > 1024 * 1024 * 1024 )
				break;
		}
	}

	static String changeCameraParam(String name) {
		Parameters ps = camera.getParameters();
		String v = ps.get(name);

		String[] vs = ps.get(name + "-values").split(",");
		int i;
		for (i = 0; i < vs.length; i++)
			if (vs[i].equals(v))
				break;
		i++;
		if (i >= vs.length)
			i = 0;
		v = vs[i];
		cameraParams.put(name, v);
		ps.set(name, v);
		camera.setParameters(ps);
		return ps.get(name);
	}

	static int changeCameraExposureCompensation() {
		Parameters ps = camera.getParameters();
		int v = ps.getExposureCompensation();
		v++;
		if (v > ps.getMaxExposureCompensation())
			v = ps.getMinExposureCompensation();
		ps.setExposureCompensation(v);
		camera.setParameters(ps);
		return camera.getParameters().getExposureCompensation();
	}

	static String changeRecordResolution() {
		Collections.rotate(recordResolutions, -2);
		stop();
		start();
		return String.format("%sx%s", recordResolutions.get(0),
				recordResolutions.get(1));
	}

	static String changeFps() {
		Collections.rotate(fps, -1);
		stop();
		start();
		return "" + fps.getFirst();
	}

	private static void onSensorChanged(SensorEvent event) {
		if( event.sensor.getType() != Sensor.TYPE_ACCELEROMETER )
			return;
		float[] v = event.values;
		double d = Math.abs(Math.sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]) - 9.8);
		if( d > maxShock )
			maxShock = d;
	}

}
